#ifndef __MCS__ASSIGNMENT_ELEMENT__HPP
#define __MCS__ASSIGNMENT_ELEMENT__HPP

#include "Element.hpp"
#include "Expression.hpp"
#include "Variable.hpp"
#include "FunctionFactory.hpp"
#include "FunctionNotFoundException.hpp"
#include "VariableNotFoundException.hpp"
#include "TypeMismatchException.hpp"

class AssignmentElement : public Element
{
public:
	AssignmentElement(SourceLocation const & location, String const & name, String const & func, ptr<Expression> expression)
		: Element(location)
		, name_(name)
		, expression_(expression)
		, func_(func)
	{}

	virtual void init(Block * parentBlock)
	{
		Element::init(parentBlock);
		variable_ = parentBlock->resolveVariable(name_);
		if(!variable_)
		{
			throw VariableNotFoundException(name_, location());
		}
		expression_->init(parentBlock);
		FunctionSignature signature(func_, 2);
		signature.addArgumentType(variable_->dataType());
		signature.addArgumentType(expression_->dataType());
		function_ = parentBlock->functionFactory()->getFunction(signature);
		if(!function_)
		{
			throw FunctionNotFoundException(signature, location());
		}
		if(variable_->dataType() != function_->returnType())
		{
			throw TypeMismatchExcepion(function_->returnType(), variable_->dataType(), location());
		}
	}

	virtual void execute() const
	{
		ptr<Value> val = expression_->evaluate();
		std::vector< ptr<Value> > args;
		args.reserve(2);
		args.push_back(variable_->value());
		args.push_back(val);
		val = function_->invoke(args);
		variable_->setValue(val);
	}
private:
	String name_;
	ptr<Variable> variable_;
	ptr<Expression> expression_;
	String func_;
	ptr<Function> function_;
};

#endif //__MCS__ASSIGNMENT_ELEMENT__HPP
